package cn.easier.activity.console.controller;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.easier.activity.console.configration.ActivityConsoleConfiguration;
import cn.easier.activity.console.entity.ActivityRoleUser;
import cn.easier.activity.console.entity.MessagePost;
import cn.easier.activity.console.entity.MessagePostRecord;
import cn.easier.activity.console.params.MessagePostParams;
import cn.easier.activity.console.repository.MessagePostRecordRepository;
import cn.easier.activity.console.repository.MessagePostRepository;
import cn.easier.activity.console.service.MessagePostQueueService;
import cn.easier.activity.console.service.MessagePostService;
import cn.easier.activity.console.utils.DelayMessage;
import cn.easier.activity.console.utils.FileUtil;
import cn.easier.club.base.dto.PageInfo;
import cn.easier.club.base.dto.ResultInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.hssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 邮短投递
 */
@RestController
@RequestMapping("/messagePost")
public class MessagePostController extends BaseController implements InitializingBean {

    Logger logger = LoggerFactory.getLogger(MessagePostController.class);
    private final MessagePostService messagePostService;
    private final MessagePostQueueService messagePostQueueService;
    private final MessagePostRepository messagePostRepository;
    private final MessagePostRecordRepository messagePostRecordRepository;
    private final ActivityConsoleConfiguration configuration;

    /**
     * 应用路径
     */
    @Value("${metadata.configuration.application-path}")
    public String applicationPath;

    @Autowired
    public MessagePostController(ActivityConsoleConfiguration configuration, MessagePostService messagePostService,
                                 MessagePostQueueService messagePostQueueService, MessagePostRepository messagePostRepository,
                                 MessagePostRecordRepository messagePostRecordRepository) {
        this.configuration = configuration;
        this.messagePostService = messagePostService;
        this.messagePostQueueService = messagePostQueueService;
        this.messagePostRepository = messagePostRepository;
        this.messagePostRecordRepository = messagePostRecordRepository;
    }

    @GetMapping("/list")
    public ResultInfo list(
            @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "size", required = false) Integer size,
            @RequestParam(value = "name", required = false) String name,
            @RequestParam(value = "timeStart", required = false) String timeStart,
            @RequestParam(value = "timeEnd", required = false) String timeEnd,
            @RequestParam(value = "type", required = false) Integer type,
            @RequestParam(value = "status", required = false) Integer status) {
        page--;
        Page<MessagePost> posts = messagePostRepository.findAll((root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (StringUtils.isNotBlank(name)) {
                predicates.add(cb.like(root.get("name"), "%" + name + "%"));
            }
            if (StringUtils.isNotBlank(timeStart)) {
                try {
                    predicates.add(cb.greaterThanOrEqualTo(root.get("createTime").as(Date.class), DateUtils.parseDate(timeStart + " 00:00:00", "yyyy-MM-dd HH:mm:ss")));
                } catch (ParseException ignored) {
                }
            }
            if (StringUtils.isNotBlank(timeEnd)) {
                try {
                    predicates.add(cb.lessThanOrEqualTo(root.get("createTime").as(Date.class), DateUtils.parseDate(timeEnd + " 23:59:59", "yyyy-MM-dd HH:mm:ss")));
                } catch (ParseException ignored) {
                }
            }
            if (type != null) {
                predicates.add(cb.equal(root.get("type"), type));
            }
            if (status != null) {
                predicates.add(cb.equal(root.get("status"), status));
            }
            ifNotAdmin(user -> predicates.add(cb.equal(root.get("creator"), user)));
            Predicate[] p = new Predicate[predicates.size()];
            return cb.and(predicates.toArray(p));
        }, new PageRequest(page, size, Sort.Direction.DESC, "createTime"));
        PageInfo<MessagePost> pageInfo = new PageInfo<>(posts.getContent(), (int) posts.getTotalElements(), size, posts.getTotalPages(), page);
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "查询成功", pageInfo);
    }

    @PostMapping("/remark")
    public ResultInfo remark(@RequestBody MessagePost param) {
        MessagePost messagePost = messagePostRepository.findOne(param.getId());
        if (messagePost == null) {
            return new ResultInfo(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), "任务不存在", null);
        }
        messagePost.setRemark(param.getRemark());
        messagePostRepository.save(messagePost);
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "保存成功", null);
    }

    @PostMapping("/send")
    public ResultInfo send(@RequestBody MessagePostParams param) {
        getUser(param::setCreator);
        if (!isAdmin()) {
            ActivityRoleUser role = getRole();
            if (role == null) {
                return new ResultInfo(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), "您没有权限进行此操作", null);
            }
            if ((param.getType() != 1 || role.getEmail() != 1) && (param.getType() != 2 || role.getMessage() != 1) && (param.getType() != 3 || role.getEmailAndSms() != 1)) {
                return new ResultInfo(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), "您没有权限进行此操作", null);
            }
        }
        if (CollectionUtils.isEmpty(param.getTarget())) {
            return new ResultInfo(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), "没有收信人", null);
        }
        // 实时发送
        if (param.getPostType() == 1) {
            messagePostService.send(param);
        } else {
            // 定时发送
            messagePostQueueService.offer(new DelayMessage(param));
        }
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "任务已添加", null);
    }

    @PostMapping("/importTargetList")
    public ResultInfo targetListFile(MultipartFile file) throws Exception {
        ImportParams params = new ImportParams();
        List<Map<String, Object>> list = ExcelImportUtil.importExcel(file.getInputStream(), Map.class, params);
        HashSet<Object> set = new HashSet<>();
        for (Map<String, Object> map : list) {
            set.addAll(map.values());
        }
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "解析完成", set);
    }

    @PostMapping("/imageUpload")
    public ResultInfo imageUpload(MultipartFile file) {
        String url = FileUtil.doFile(file, configuration.realPath + configuration.messagePostImagePath, "email_");
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "上传完成", applicationPath.replace("activityConsole", "ActivityWeb/static/") + configuration.messagePostImagePath + url);
    }

    @GetMapping("/downloadTemplate")
    public void downloadTemplate(@RequestParam("type") Integer type, HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=template.xls");
        OutputStream out = response.getOutputStream();
        createEmailTemplate(type).write(out);
        out.close();
    }

    @GetMapping("/record/list")
    public ResultInfo recordList(
            @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "size", required = false) Integer size,
            @RequestParam(value = "name", required = false) String name,
            @RequestParam(value = "timeStart", required = false) String timeStart,
            @RequestParam(value = "timeEnd", required = false) String timeEnd,
            @RequestParam(value = "type", required = false) Integer type,
            @RequestParam(value = "target", required = false) String target,
            @RequestParam(value = "status", required = false) Integer status) {
        page--;
        if (StringUtils.isBlank(name)) {
            name = null;
        } else {
            name = "%" + name + "%";
        }
        if (StringUtils.isBlank(timeStart)) {
            timeStart = null;
        } else {
            timeStart += " 00:00:00";
        }
        if (StringUtils.isBlank(timeEnd)) {
            timeEnd = null;
        } else {
            timeEnd += " 23:59:59";
        }
        if (StringUtils.isBlank(target)) {
            target = null;
        }
        AtomicReference<String> creator = new AtomicReference<>();
        ifNotAdmin(creator::set);
        Page<Object[]> postRecords = messagePostRecordRepository.findAll(name, timeStart, timeEnd, type, target, status, creator.get(), new PageRequest(page, size, Sort.Direction.DESC, "id"));
        List<Map<String, Object>> list = new ArrayList<>();
        for (Object[] records : postRecords.getContent()) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("id", records[0]);
            map.put("name", records[1]);
            map.put("phoneNum", records[2]);
            Object record3 = records[3];
            if (record3 != null) {
                map.put("time", DateFormatUtils.format((Date) record3, "yyyy-MM-dd HH:mm:ss"));
            } else {
                map.put("time", "");
            }
            map.put("type", records[4]);
            map.put("status", records[5]);
            map.put("remark", records[6]);
            list.add(map);
        }
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(list, (int) postRecords.getTotalElements(), size, postRecords.getTotalPages(), page);
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "查询成功", pageInfo);
    }

    @PostMapping("/record/remark")
    public ResultInfo recordRemark(@RequestBody MessagePostRecord param) {
        MessagePostRecord messagePostRecord = messagePostRecordRepository.findOne(param.getId());
        if (messagePostRecord == null) {
            return new ResultInfo(String.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR), "任务不存在", null);
        }
        messagePostRecord.setRemark(param.getRemark());
        messagePostRecordRepository.save(messagePostRecord);
        return new ResultInfo(String.valueOf(HttpServletResponse.SC_OK), "保存成功", null);
    }

    @GetMapping("/record/export")
    public void recordExport(@RequestParam(value = "name", required = false) String name,
                             @RequestParam(value = "timeStart", required = false) String timeStart,
                             @RequestParam(value = "timeEnd", required = false) String timeEnd,
                             @RequestParam(value = "type", required = false) Integer type,
                             @RequestParam(value = "target", required = false) String target,
                             @RequestParam(value = "status", required = false) Integer status,
                             HttpServletResponse response) throws IOException {
        if (StringUtils.isBlank(name)) {
            name = null;
        } else {
            name = "%" + name + "%";
        }
        if (StringUtils.isBlank(timeStart)) {
            timeStart = null;
        } else {
            timeStart += " 00:00:00";
        }
        if (StringUtils.isBlank(timeEnd)) {
            timeEnd = null;
        } else {
            timeEnd += " 23:59:59";
        }
        if (StringUtils.isBlank(target)) {
            target = null;
        }
        AtomicReference<String> creator = new AtomicReference<>();
        ifNotAdmin(creator::set);
        Page<Object[]> postRecords = messagePostRecordRepository.findAll(name, timeStart, timeEnd, type, target, status, creator.get(), new PageRequest(0, Integer.MAX_VALUE));
        List<Map<String, String>> list = new ArrayList<>();
        for (Object[] records : postRecords.getContent()) {
            HashMap<String, String> map = new HashMap<>();
            map.put("编号", String.valueOf(records[0]));
            map.put("投递任务名称", String.valueOf(records[1]));
            map.put("收信人", String.valueOf(records[2]));
            Date record3 = (Date) records[3];
            if (record3 != null) {
                map.put("投递时间", DateFormatUtils.format(record3, "yyyy-MM-dd HH:mm:ss"));
            } else {
                map.put("投递时间", "");
            }
            byte record4 = (byte) records[4];
            switch (record4) {
                case 1:
                    map.put("投递类型", "邮件");
                    break;
                case 2:
                    map.put("投递类型", "短信");
                    break;
                case 3:
                    map.put("投递类型", "邮短");
                    break;
                default:
                    map.put("投递类型", "");
            }
            byte record5 = (byte) records[5];
            switch (record5) {
                case 1:
                    map.put("投递状态", "投递成功");
                    break;
                case 2:
                    map.put("投递状态", "投递失败");
                    break;
                default:
                    map.put("投递状态", "");
            }
            map.put("备注", (String) records[6]);
            list.add(map);
        }
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("投递记录");
        HSSFRow row0 = sheet.createRow(0);
        List<String> titleList = Arrays.asList("编号", "投递任务名称", "收信人", "投递时间", "投递类型", "投递状态", "备注");
        for (int j = 0; j < titleList.size(); j++) {
            HSSFCell cell = row0.createCell(j);
            cell.setCellValue(titleList.get(j));
        }
        for (int i = 0; i < list.size(); i++) {
            Map<String, String> map = list.get(i);
            HSSFRow row = sheet.createRow(i + 1);
            for (int j = 0; j < titleList.size(); j++) {
                HSSFCell cell = row.createCell(j);
                cell.setCellValue(map.get(titleList.get(j)));
            }
        }
        sheet.autoSizeColumn((short) 0);
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=" + new String("投递记录".getBytes(), StandardCharsets.ISO_8859_1) + ".xls");
        workbook.write(response.getOutputStream());
    }

    /**
     * 创建收件人上传文件模板
     */
    private HSSFWorkbook createEmailTemplate(Integer type) {
        HSSFWorkbook sheets = new HSSFWorkbook();
        HSSFCellStyle cellStyle = sheets.createCellStyle();
        HSSFSheet sheet = sheets.createSheet("收信人列表");
        HSSFRow row0 = sheet.createRow(0);
        HSSFRow row1 = sheet.createRow(1);
        HSSFCell cell00 = row0.createCell(0);
        cell00.setCellStyle(cellStyle);
        HSSFPatriarch drawingPatriarch = sheet.createDrawingPatriarch();
        HSSFComment comment = drawingPatriarch.createCellComment(new HSSFClientAnchor(0, 0, 0, 0, (short) 4, 2, (short) 10, 5));
        comment.setString(new HSSFRichTextString("必须保留这一行\n在下面填写收件人" + (type == 1 ? "邮箱" : "手机号")));
        cell00.setCellComment(comment);
        HSSFCell cell10 = row1.createCell(0);
        cell00.setCellValue("收件人列表");
        cell10.setCellValue(type == 1 ? "xxxx@xxx.xx" : "185xxxxxxxx");
        sheet.autoSizeColumn((short) 0);
        return sheets;
    }

    /**
     * 初始化之后异步执行，用于初始化队列
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        messagePostQueueService.queue();
    }
}